#include "head.h"

int recvn(int netfd, void *buf, int length)
{
    int total = 0;
    int ret;
    char *p = (char *)buf;
    while (total < length)
    {
        ret = recv(netfd, p + total, length - total, 0);
        if (ret == 0) // 进来说明没收完，没收完返回值却是0则说明对面断开了，可以退出
        {
            return 0;
        }
        total += ret;
    }
    return 0;
}

int recvFile(int netfd, off_t offset)
{
    // 接收到文件名先加上".filepart"后缀
    char file_name[1000] = {0};
    char file_name_nopart[1000] = {0}; // 没有.filepart后缀的文件名
    train_t train;
    bzero(&train, sizeof(train_t));
    recv(netfd, &train.length, sizeof(int), MSG_WAITALL);
    if (train.length == 0)
    {
        printf("wrong file name!\n");
        return -1;
    }
    recv(netfd, file_name, train.length, MSG_WAITALL);
    strcpy(file_name_nopart, file_name);
    // printf("file name is %s\n",train.data);
    strcat(file_name, ".filepart");
    strcat(file_name, "\0");
    char path[1000] = {0};
    sprintf(path, "download/%s", file_name);
    int fd = open(path, O_CREAT | O_RDWR, 0666);
    // 先接收原文件大小
    off_t fileSize;
    bzero(&train, sizeof(train_t));
    recv(netfd, &train.length, sizeof(int), MSG_WAITALL);
    recv(netfd, train.data, train.length, MSG_WAITALL);
    memcpy(&fileSize, train.data, train.length);
    // printf("fileSize = %ld\n",fileSize);
    if (offset != 0)
    { // 续传未完成文件
        off_t ret = lseek(fd, offset, SEEK_SET);
        printf("ret = %ld\n", ret);
        ERROR_CHECK(ret, -1, "lseek");
    }

    if (fileSize >= 1073741824)
    { // 大于1G，一次性接收
        ftruncate(fd, fileSize);
        char *p = (char *)mmap(NULL, fileSize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
        ERROR_CHECK(p, MAP_FAILED, "mmap");
        recvn(netfd, p, fileSize);
        munmap(p, fileSize);
    }
    else
    { // 分批接收
        long curSize = offset;
        long lastSize = offset;
        long slice = fileSize / 1000;
        while (1)
        {
            bzero(&train, sizeof(train));
            int ret = recv(netfd, &train.length, sizeof(train.length), MSG_WAITALL);
            if (train.length == 0)
            {
                printf("file is recived!\n");
                break;
            }
            else if (ret == 0)
            { // 对面提前断开
                return -1;
            }
            recv(netfd, train.data, train.length, MSG_WAITALL);
            write(fd, train.data, train.length);
            curSize += train.length;
            if (curSize < fileSize)
            {
                if (curSize - lastSize > slice)
                {
                    printf("%5.2lf%%\r", 100.0 * curSize / fileSize);
                    fflush(stdout);
                    lastSize = curSize;
                }
            }
        }
        printf("100.00%%\n");
    }
    // 改文件名去掉.filepart
    char newPath[1024] = {0};
    sprintf(newPath, "download/%s", file_name_nopart);
    rename(path, newPath);
    printf("download succeeded\n");
    close(fd);
    return 0;
}